#!/bin/python3
# -*- coding:utf-8 -*-
"""
    [模块名]
    By :陈狍子 e4ting@qq.com 2024-12-07 22:10:24
"""
import sys,os,time,json
from pdb import set_trace as strace
from traceback  import format_exc as dumpstack

from transitions import Machine
from setproctitle import getproctitle,setproctitle
from e4ting import util,log

from .roomseat import Seat
from .game     import Game
from .player   import GamePlayer
from .cash     import Utxo,VirtualAccount

from core.control import Notify
from models.mysqls import ModelCash,ModelRoom,ModelRoomSeat,db
from core.cache    import RoomCache

class Room():
    states = ['create', 'prepare', 'gaming', 'stoping', 'deleted']
    actions = ['_start', '_gaming', '_stop', '_quit']
    transitions = [
        {'trigger':  '_create', 'source':        '', 'dest': 'create', 'after': 'after_state_change'},

        {'trigger':  '_start', 'source':  'create', 'dest': 'prepare', 'after': 'after_state_change'},
        # {'trigger':  '_start', 'source': 'prepare', 'dest': 'prepare', 'after': 'after_state_change'},
        {'trigger':  '_start', 'source':  'gaming', 'dest': 'prepare', 'after': 'after_state_change'},

        {'trigger': '_gaming', 'source': 'prepare', 'dest':  'gaming', 'after': 'after_state_change'},
        {'trigger': '_gaming', 'source': 'stoping', 'dest':  'gaming', 'after': 'after_state_change'},

        {'trigger':   '_stop', 'source':  'create', 'dest': 'stoping', 'after': 'after_state_change'},
        {'trigger':   '_stop', 'source': 'prepare', 'dest': 'stoping', 'after': 'after_state_change'},
        {'trigger':   '_stop', 'source':  'gaming', 'dest': 'stoping', 'after': 'after_state_change'},

        {'trigger':   '_quit', 'source':  'create', 'dest': 'deleted', 'after': 'after_state_change'},
        {'trigger':   '_quit', 'source': 'prepare', 'dest': 'deleted', 'after': 'after_state_change'},
        # {'trigger':   '_quit', 'source':  'gaming', 'dest': 'deleted', 'after': 'after_state_change'},
        {'trigger':   '_quit', 'source': 'stoping', 'dest': 'deleted', 'after': 'after_state_change'},
    ]
    max_seat = 10

    def __init__(self, uid=0):
        self.uid = uid
        # 玩家
        self.players = []
        # 观众
        self.visists = []
        # 座位
        self.seats   = [ Seat(i) for i in range(Room.max_seat) ]
        self.machine = Machine(model=self, states=Room.states, transitions=Room.transitions, initial=Room.states[0])

    def after_state_change(self):
        log.info(f"房间状态切换: {self.state}")
        self.cache.status = self.state

    def on_enter_delted(self):
        log.info("删除房间")

    def build_cache(self, uid=None):
        uid = uid or self.uid
        item = db.session.query(ModelRoom).filter(ModelRoom.id==uid).first()
        if not item:
            return False
        self.cache.set(**item.to_json())
        return True

    @property
    def cache(self):
        cache = RoomCache(self.uid)
        if not cache.exists():
            cache.set(__time__=util.now())
        return cache

    def init(self):
        self.sender  = Notify(self.uid)

        self.bank   = VirtualAccount.get_bank() # 银行
        self.dealer = VirtualAccount(uid=f"dealer{self.uid}").init() # 荷官，用来存一些临时信息，比如结算时剩下的零头
        self.dealer.create_record(name=f"荷官-{self.uid}", detail=f"房间{self.uid}的荷官")

        self.cache.set(bank=self.bank.uid, dealer=self.dealer.uid)

        [ s.set_room(self) for s in self.seats]

        self.upadte()
        self._start()

    def upadte(self, judge=None):
        db.session.query(ModelRoom).filter(ModelRoom.id==self.uid).update({
                ModelRoom.bank  : self.bank.uid,
                ModelRoom.dealer: self.dealer.uid,
                ModelRoom.judge : judge.uid if judge else "",
            })

    def exists(self, uid=None):
        uid = uid or self.uid
        item = db.session.query(ModelRoom).filter(ModelRoom.id==uid).first()
        if not item:
            return False
        return True

    def update_game(self, game=None):
        self.cache.game = game.webdump()

    def create_seats(self):
        for n in range(Room.max_seat):
            Seat(n).set_room(self).create_record()

    def create_record(self, name, detail=""):
        item = ModelRoom(
                bank="",
                dealer="",
                judge="",
                name=name,
                detail=detail)
        db.session.add(item)
        db.session.commit()
        self.uid = item.id
        # strace()
        return self.uid

    def broadcast(self, msg):
        self.sender.notify(msg)

    def send_commons(self, faces=[]):
        self.sender.commons(faces)

    def send_progress(self, uid, progress):
        self.sender.progress(uid, progress)

    def send_all_hands(self, faces=[]):
        if faces:
            return self.sender.all_hands(faces)
        return self.sender.all_hands([ player.face_dump() for player in self.players ])

    def send_all_rate(self):
        return self.sender.all_rates([ player.rate_dump() for player in self.players ])

    def clear_all_rate(self):
        return self.sender.all_rates([ {"card_type": ""} for player in self.players ])

    def sleep(self, sec=1):
        for i in range(sec+1):
            self.send_progress("dealer", int(100*i/sec))
            time.sleep(1)

    def add_players(self, uid, seat=0):
        self.cache.players

    def add_visist(self, uid):
        self.cache.visists

    def get_sit_players(self):
        player_ids = json.loads(self.cache.players or "[]") or []
        return [ GamePlayer(index=item['index'], uid=item['uid'], room=self) for item in player_ids ]

    def get_visist(self):
        # 访客列表
        player_ids = self.cache.visists
        return []

    def prepare(self, flag=0):
        """ 准备阶段-等待玩家 """
        if (flag % 59) == 0:
            log.info(self.prepare.__doc__)
        # 进入准备阶段
        if not self.is_prepare():
            self._start()
        self.broadcast( self.prepare.__doc__.strip() )
        # self.players = [
        #     GamePlayer(index=i, uid=f"robot{i}", room=self) for i in range(4)
        # ] # + [ GamePlayer(2, auto=False) ]
        self.players = self.get_sit_players()
        self.visists = self.get_visist()

        # title = getproctitle()
        setproctitle(f"python3 -m game.core [ {self.cache.name} {len(self.players)}玩家 {len(self.visists)}访客 ] - {flag}")

        if len(self.players) < 2:
            return False
        # self.cache.players = [p.webdump() for p in self.players]
        # self.cache.visists = [p.webdump() for p in self.visists]
        self.broadcast( "玩家已就绪" )
        return True

    def run(self):
        btn = self.cache.change(btn=1)
        while btn <= (1<<26):
            btn = self.cache.change(btn=1)
            if not self.prepare(flag=btn):
                self.sleep(1)
                continue
            self._gaming()
            game = Game(btn=btn, room=self)
            game.init()
            game.set_players(self.players)
            game.run()
            self._stop()
            # break
            self.sleep(15)
        self._quit()
        return

    def stop(self):
        return

    def __repr__(self):
        return f"Room({self.uid})"

if __name__ == '__main__':
    room = Room()
    room.run()
